/**
 *
 * History:
 *   2010-7-5 19:33:22 Created by ZGong
 */
package gz.gae.blog.impl;

import com.google.appengine.api.datastore.Key;
import gz.gae.blog.FileDataManager;
import gz.gae.blog.cache.CacheUtil;
import gz.gae.blog.entity.BigBlob;
import gz.gae.blog.entity.Block;
import gz.gae.blog.entity.FileData;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

/**
 * Created by ZGong.
 *
 * @version 1.0 2010-7-5 19:33:22
 */
@Transactional
public class CachedFileDataManager
        extends FileDataManagerImpl
        implements FileDataManager {
    public static final String KEY_PPEFIX = "FILE_DATA_";
    private static final Logger log = Logger.getLogger(CachedFileDataManager.class.getName());

    public void add(FileData fileData) {
        super.add(fileData);
        //  cache.put(getCacheKey(fileData.getId()), fileData);
    }

    public void remove(long id) {
        super.remove(id);
        Object o = CacheUtil.get(getCacheKey(id));
        if (o != null) {
            FileData data = ((CachedFileData) o).getFd();
            List<Block> list = data.getBigBlob().getBlobList();
            for (Block b : list) {
                CacheUtil.remove(b.getKey());
            }
        }
        CacheUtil.remove(getCacheKey(id));
    }

    public FileData get(long id) {
        FileData data;
        Object o = CacheUtil.get(getCacheKey(id));
        if (o == null) {
            data = super.get(id);
            if (data != null) {
                CacheUtil.put(getCacheKey(id), getCachedFile(data));
            }
        } else {
            data = ((CachedFileData) o).getFd();
            log.info("get from cache:" + id);
        }
        return data;
    }

    private Object getCachedFile(FileData data) {
        return new CachedFileData(data);
    }

    private String getCacheKey(long id) {
        return KEY_PPEFIX + id;
    }

    public void update(FileData fileData) {
        super.update(fileData);
        CacheUtil.remove(getCacheKey(fileData.getId()));
    }

    private static class CachedFileData
            implements Serializable {
        transient FileData fd;

        CachedFileData(FileData fd) {
            this.fd = fd;
        }

        public FileData getFd() {
            return fd;
        }

        public void setFd(FileData fd) {
            this.fd = fd;
        }

        private void writeObject(java.io.ObjectOutputStream out)
                throws IOException {
            BigBlob bigBlob = fd.getBigBlob();
            List<Block> list = bigBlob.getBlobList();

            out.writeLong(fd.getId());
            out.writeUTF(fd.getContentType());
            out.writeObject(fd.getCreateDate());
            out.writeUTF(fd.getFileName());
            out.writeLong(fd.getSize());
            out.writeObject(bigBlob.getKey());
            out.writeInt(list.size());

            for (Block b : list) {
                out.writeObject(b.getKey());
                CacheUtil.put(b.getKey(), b);
            }
            out.close();
        }

        private void readObject(java.io.ObjectInputStream in)
                throws IOException, ClassNotFoundException {
            fd = new FileData();
            BigBlob bigBlob = new BigBlob();
            fd.setBigBlob(bigBlob);

            fd.setId(in.readLong());
            fd.setContentType(in.readUTF());
            fd.setCreateDate((Date) in.readObject());
            fd.setFileName(in.readUTF());
            fd.setSize(in.readLong());
            bigBlob.setKey((Key) in.readObject());
            int n = in.readInt();

            for (int i = 0; i < n; i++) {
                Object o = in.readObject();
                Key key = (Key) o;
                Object o1 = CacheUtil.get(key);
                Block b = (Block) o1;
                bigBlob.getBlobList().add(b);
            }
            in.close();
        }
    }
}
